#include "Serializer.h"
#include "NetworkPacket.h"
#include "MovingObject.h"
#include "PlayerObject.h"
#include "AttackObject.h"
#include "EnemyObject.h"
#include "Logging.h"
#include <sstream>

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/base_object.hpp>

#ifdef _WIN32
#include <windows.h>
#endif

Serializer::Serializer()
{
}

namespace boost {
namespace serialization
{
	template< class _Archive >
	/*inline*/void serialize( _Archive& ar, PlayerObject& playerObject, const unsigned int version)
	{
		ar & *playerObject.getMovementInfo();
//		ar & *playerObject.getPlayerIndex();
		ar & playerObject.name;
		ar & playerObject.position;
		ar & playerObject.mat;
		ar & playerObject.isDead;
		ar & playerObject.killCount;
	//	ar & *((((core::vector3df*)&playerObject.getPosition()))); // rip  based god
	};
	
	template< class _Archive >
	/*inline*/void serialize( _Archive& ar, EnemyObject& enemyObject, const unsigned int version)
	{
		ar & *enemyObject.getMovementInfo();
		ar & enemyObject.position;
		ar & enemyObject.mat;
		ar & enemyObject.enemyMapKey;
		ar & enemyObject.isDead;
		ar & enemyObject.ID;
	};

	template< class _Archive >
	/*inline*/void serialize( _Archive& ar, AttackObject& projectileObject, const unsigned int version)
	{
		ar & projectileObject.position;
		ar & projectileObject.attackType;
	 	ar & projectileObject.mat;
	 	ar & projectileObject.ID;
	 	ar & projectileObject.originatingPlayer;
	};

	template< class _Archive >
	/*inline*/void serialize( _Archive& ar, MovementInfo& movementInfo, const unsigned int version)
	{
		ar & movementInfo.startPos;
		ar & movementInfo.destinationPos;
		ar & movementInfo.moveSpeed;
		ar & movementInfo.timesMoved;
		ar & movementInfo.timesToMove;
	};
	
	template< class _Archive >
	/*inline*/void serialize( _Archive& ar, core::vector3df& pos, const unsigned int version)
	{
		ar & pos.X;
		ar & pos.Y;
		ar & pos.Z;
	};

	template< class _Archive >
	/*inline*/void serialize( _Archive& ar, core::matrix4& mat, const unsigned int version)
	{
		ar & mat[0];
		ar & mat[1];
		ar & mat[2];
		ar & mat[3];
	};
	
	template< class _Archive >
	/*inline*/void serialize( _Archive& ar, NetworkPacket& networkPacket, const unsigned int version)
	{
		ar & networkPacket.first;
		ar & networkPacket.second;
	};
	
}
}

BOOST_CLASS_IMPLEMENTATION(MovementInfo, boost::serialization::object_class_info);
BOOST_CLASS_TRACKING(MovementInfo, boost::serialization::track_never);

BOOST_CLASS_IMPLEMENTATION(core::vector3df, boost::serialization::object_class_info);
BOOST_CLASS_TRACKING(core::vector3df, boost::serialization::track_never);

BOOST_CLASS_IMPLEMENTATION(core::matrix4, boost::serialization::object_class_info);
BOOST_CLASS_TRACKING(core::matrix4, boost::serialization::track_never);

BOOST_CLASS_IMPLEMENTATION(NetworkPacket, boost::serialization::object_class_info);
BOOST_CLASS_TRACKING(NetworkPacket, boost::serialization::track_never);

BOOST_CLASS_IMPLEMENTATION(std::vector<NetworkPacket>, boost::serialization::object_class_info);
BOOST_CLASS_TRACKING(std::vector<NetworkPacket>, boost::serialization::track_never);

BOOST_CLASS_IMPLEMENTATION(AttackObject, boost::serialization::object_class_info);
BOOST_CLASS_TRACKING(AttackObject, boost::serialization::track_never);

std::string Serializer::callSerialize(uintptr_t pointer, HeaderType headerType)
{
	std::stringstream ss;
	
	try
	{
		boost::archive::text_oarchive oa(ss);
		switch(headerType)
		{
			case PLAYEROBJECTVECTOR:
				oa << *(std::vector<PlayerObject>*)pointer; 
			break;
			case PLAYEROBJECT:
				oa << *(PlayerObject*)pointer; 
			break;
			case PACKETBUNDLE:
				oa << *(std::vector<NetworkPacket>*)pointer; 
			break;
			case ATTACKOBJECT:
				oa << *(AttackObject*)pointer;
			break;
			case ATTACKOBJECTVECTOR:
				oa << *(std::vector<AttackObject>*)pointer;
			break;
			case ENEMYOBJECT:
				oa << *(EnemyObject*)pointer;
			break;
			case ENEMYOBJECTVECTOR:
				oa << *(std::vector<EnemyObject>*)pointer;
			break;
			default:
				std::cout << "CASE" << headerType << " NOT HANDLED IN callSerialize!\n";
				assert(" " == 0);
			break;
		} 
	}
	catch(std::exception& e)
	{
		std::cout << "Exception din farsa\n";
	}	
		
	return ss.str();
}

bool Serializer::callDeserialize(uintptr_t passedPointer, HeaderType headerType, const std::string& serializedStr)
{	
	std::istringstream ss2(serializedStr);
	
	try
	{
		boost::archive::text_iarchive ia(ss2);

		switch(headerType)
		{
			case PLAYEROBJECTVECTOR:
				ia >> *(std::vector<PlayerObject>*)passedPointer;
			break;
			case PLAYEROBJECT:
				ia >> *(PlayerObject*)passedPointer;
			break;
			case PACKETBUNDLE:
				ia >> *(std::vector<NetworkPacket>*)passedPointer;
			break;
			case ATTACKOBJECT:
				ia >> *(AttackObject*)passedPointer;
			break;
			case ATTACKOBJECTVECTOR:
				ia >> *(std::vector<AttackObject>*)passedPointer;
			break;
			case ENEMYOBJECT:
				ia >> *(EnemyObject*)passedPointer;
			break;
			case ENEMYOBJECTVECTOR:
				ia >> *(std::vector<EnemyObject>*)passedPointer;
			break;
			default:
				std::cout << "CASE" << headerType << " NOT HANDLED IN callDeserialize!\n";
				assert(" " == 0);
			break;
		}
	}
	catch(std::exception& e)
	{
		std::cout << "Deserialization exception (bool story).\n";
//		logMessage("\n\n\nFAILED:" +serializedStr +"\n\n\n");
		return false;
	}
//	logMessage("\n\n\nSUCCESSFUL:" +serializedStr +"\n\n\n");
	return true;
}
//qzxcq
